import { IOperationNode } from './operation-node';
import { SwitchNode } from './switch-node';
import { ExecuteNode, OperationExtendLevel } from './execute-node';
import {
    WebCommand, ICommandItem, CmpMethodRefering, BranchCollectionCommandItem, BranchCommandItem, WebCommandMetadata
} from '@farris/designer-services';
import { OperationCollection } from './operation-collection';
import { ITreeNode } from './tree-node';
import { ParamConfig } from './param';
import { Extension } from './extension';
import { Case } from './case';

export class Command implements ITreeNode {
    private webCommand: WebCommand;


    get data(): { id: string; name: string; code: string, description: string, controllerCode?: string, controllerName?: string } {
        return { id: this.id, name: this.name, code: this.code, description: this.description, controllerCode: this.controllerCode, controllerName: this.controllerName };
    }

    get children(): ITreeNode[] {
        return this.handlers;
    }

    expanded?: boolean;

    id: string;

    code: string;

    name: string;

    params: ParamConfig[] = [];

    cmpId: string;

    handlerName: string;

    extensions: Extension[] = [];

    handlers: OperationCollection;

    shortcut?: any;

    root: ITreeNode;

    /** 是否为运行时定制添加的命令 */
    isRTCmd?: boolean;

    /** 命令的参数是否需要刷新--用于构件中删除命令参数的场景 */
    needRefreshParam: boolean;

    /** 命令是否已失效（被删除） */
    isInValid?= false;

    /** 命令描述信息 */
    description?: string;

    /** 命令所属控制器的名称 */
    controllerName?: string;

    /** 命令所属控制器的编号 */
    controllerCode?: string;

    isNewGenerated?: boolean;

    targetComponent?: string;

    /**
     * 构造命令信息
     * @param webCommand 构件中的命令结构
     * @param commandJsonOrCmpId 表单中记录的命令结构或者构件id
     */
    constructor(webCommand: WebCommand, commandJsonOrCmpId: any | string, webCmd?: WebCommandMetadata) {
        if (!webCommand) {
            console.warn('参数错误，webCommand不能为空！ 无效的命令');
            return;
        }
        this.root = this;
        this.webCommand = webCommand;

        this.handlerName = this.webCommand.Code;
        if (this.webCommand.Description === '此处添加方法描述') {
            this.webCommand.Description = '';
        }
        if (typeof commandJsonOrCmpId === 'string') {
            // todo: 先使用构件命令的参数  在新建之后需要更新--actions-builder.ts中处理
            this.id = this.webCommand.Id;
            this.code = this.webCommand.Code;
            this.name = this.webCommand.Name;
            this.cmpId = commandJsonOrCmpId;
            this.description = this.webCommand.Description;
            this.extensions = [];
            this.addParamFromWebCommand();
        } else {
            this.id = commandJsonOrCmpId.id;
            this.code = commandJsonOrCmpId.code;
            this.name = commandJsonOrCmpId.name;
            this.description = this.webCommand.Description;
            this.cmpId = commandJsonOrCmpId.cmpId;
            this.isNewGenerated = commandJsonOrCmpId.isNewGenerated;
            this.targetComponent = commandJsonOrCmpId.targetComponent;
            this.extensions = [];

            // 添加快捷键配置
            this.shortcut = commandJsonOrCmpId.shortcut || {};

            if (commandJsonOrCmpId.extensions) {
                for (const extensionJson of commandJsonOrCmpId.extensions) {
                    const ext = new Extension(extensionJson);
                    ext.root = this;
                    this.extensions.push(ext);
                }
            }

            this.params = [];
            // 先加载表单记录的参数信息，再从构件中加载参数
            if (commandJsonOrCmpId.params && commandJsonOrCmpId.params.length) {
                for (const paramJson of commandJsonOrCmpId.params) {
                    this.params.push(new ParamConfig(paramJson));
                }
            }
            this.addParamFromWebCommand();
        }

        if (webCmd) {
            this.controllerCode = webCmd.Code;
            this.controllerName = webCmd.Name;
        }

        this.handlers = new OperationCollection();
        this.handlers.push(...this.loadHandlers(this.webCommand.Items, this.getExtensionMap()));

        // this.data = { id: this.id, name: this.name };
        // this.children = this.handlers;
    }

    toJson() {
        const result: any = {
            id: this.id,
            code: this.code,
            name: this.name,
            params: [],
            handlerName: this.handlerName,
            cmpId: this.cmpId,
            shortcut: this.shortcut ? JSON.parse(JSON.stringify(this.shortcut)) : {},
            extensions: [],
            isRTCmd: this.isRTCmd,
            isInvalid: this.isInValid
        };
        if (this.isNewGenerated !== undefined) {
            result.isNewGenerated = this.isNewGenerated;
        }
        if (this.targetComponent !== undefined) {
            result.targetComponent = this.targetComponent;
        }
        // param
        for (const param of this.params) {
            result.params.push(param.toJson());
        }

        // extension
        for (const extension of this.extensions) {
            result.extensions.push(extension.toJson());
        }

        return result;
    }

    /* #region private methods */
    /**
     * 扩展信息放入map中.
     * key是position最后一个guid，即被扩展节点的id.
     * value是数组，一个节点可能有最多三种扩展：操作前，操作后，替换
     */
    private getExtensionMap() {
        const map = new Map<string, Extension[]>();
        for (const extension of this.extensions) {
            const positionJson = extension.position;
            let pos: string;
            if (typeof positionJson === 'string') {
                pos = positionJson;
            } else {
                pos = positionJson[extension.position.length - 1];
            }
            if (map.has(pos)) {
                map.get(pos).push(extension);
            } else {
                map.set(pos, [extension]);
            }
        }
        return map;
    }

    private loadHandlers(items: ICommandItem[], extensionMap: Map<string, Extension[]>) {
        const handlers = new Array<IOperationNode & ITreeNode>();
        for (const item of items) {
            let handler: ExecuteNode | SwitchNode;
            if (item instanceof CmpMethodRefering) {
                handler = new ExecuteNode();
                handler.id = item.Id;
                handler.code = item.Code;
                handler.name = item.Name;
                handler.method = item.MethodCode;
                handler.methodName = item.MethodName;
                handler.cmpCode = item.ComponentCode;
                handler.extendLevel = OperationExtendLevel.Comp;
                handler.componentName = item.ComponentName;
                handler.componentCode = item.ComponentCode;

                // 可扩展性
                handler.preExtendable = item.IsBeforeExpansion;
                handler.replaceable = item.IsReplaced;
                handler.postExtendable = item.IsAfterExpansion;

                handler.root = this;

                // 处理扩展
                const extensions = extensionMap.get(handler.id);
                let beforeExtension: Extension, replaceExtension: Extension, afterExtension: Extension;
                if (extensions && extensions.length) {
                    for (const extension of extensions) {
                        switch (extension.type) {
                            case 'InsertBefore':
                                beforeExtension = extension;
                                break;
                            case 'Replace':
                                replaceExtension = extension;
                                break;
                            case 'InsertAfter':
                                afterExtension = extension;
                                break;
                            default:
                                break;
                        }
                    }
                }

                if (beforeExtension && item.IsBeforeExpansion) {
                    // handlers.push(beforeExtension);
                    handler.preExtension = beforeExtension;
                }
                if (replaceExtension && item.IsReplaced) {
                    // handlers.push(...replaceExtension.tasks);
                    handler.replaceExtension = replaceExtension;
                    handler.replaced = true;
                }
                handlers.push(handler);
                if (afterExtension && item.IsAfterExpansion) {
                    // handlers.push(...afterExtension.tasks);
                    handler.postExtension = afterExtension;
                }
            } else if (item instanceof BranchCollectionCommandItem) {
                handler = new SwitchNode();
                handler.id = item.Id;
                handler.name = item.Name;
                handler.root = this;
                handler.cases = [];
                for (const subItem of item.Items) {
                    if (subItem instanceof BranchCommandItem) {
                        const casee = new Case();
                        casee.id = subItem.Id;
                        casee.name = subItem.Name;
                        casee.condition = subItem.Express;
                        casee.root = this;
                        casee.handlers = new OperationCollection();
                        casee.handlers.push(...this.loadHandlers(subItem.Items, extensionMap));
                        handler.cases.push(casee);
                    }
                }

                handlers.push(handler);
            }
        }

        return handlers;
    }

    /**
     * 标识已移除的参数
     * @param params 已有的参数
     * @param webCommand 构件中记录的参数
     */
    private processParams(params: any[], webCommand: any[]) {
        const webCommandCode = webCommand.map(item => item.Code);
        params.forEach(param => {
            if (!webCommandCode.includes(param.name)) {
                param['isDisused'] = true;
            }
        });
    }

    /**
     * 追加命令的参数：表单viewModel中没有，但是构件中有的参数
     * 对比方式：表单viewModel.command.name===构件命令Code( 构件的命令编号不能随意更改)
     */
    private addParamFromWebCommand() {
        if (!this.params) { this.params = []; }
        if (!this.webCommand || !this.webCommand.Parameters) { return; }

        // 标识已移除的参数
        this.processParams(this.params, this.webCommand.Parameters);

        for (const parameter of this.webCommand.Parameters) {
            const existingParam = this.params.find(item => item.name === parameter.Code);
            if (existingParam) {
                // 存在的参数，更新类型、名称、说明
                existingParam.type = parameter.ParameterType;
                existingParam.shownName = parameter.Name;
                existingParam['EditorType'] = parameter['EditorType'];
                existingParam.description = parameter.Description;
                existingParam.controlSource = parameter['controlSource'];
                existingParam.defaultValue = parameter['defaultValue'];
                continue;
            }

            // 新增的参数
            const param = new ParamConfig();
            param.name = parameter.Code;
            param.shownName = parameter.Name;
            param.type = parameter.ParameterType;
            param['EditorType'] = parameter && parameter['EditorType'] ? parameter['EditorType'] : null;
            param.value = '';
            param.description = parameter.Description;
            param.controlSource = parameter['controlSource'];
            param.defaultValue = parameter['defaultValue'];

            this.params.push(param);
        }

    }

    /* #endregion */
    private parseshortcut() {

    }
}
